using System;
using System.Text;
using System.Text.RegularExpressions;
using Antu.Core.Services;

namespace Antu.Core.Ajax
{
    /// <summary>
    /// Provides methods to serialize and deserialize a DateTime object.
    /// </summary>
    public class DateTimeConverter : AbstractJavascriptConverter
    {
        private Regex r = new Regex( @"(\d{4}),(\d{1,2}),(\d{1,2}),(\d{1,2}),(\d{1,2}),(\d{1,2}),(\d{1,3})" , RegexOptions.Compiled );
        private double UtcOffsetMinutes = TimeZone.CurrentTimeZone.GetUtcOffset( DateTime.Now ).TotalMinutes;
        SerializerService _SerializerService = (SerializerService)ServiceManager.Manager.GetService(typeof(SerializerService));
        /// <summary>
        /// Initializes a new instance of the <see cref="DateTimeConverter"/> class.
        /// </summary>
        public DateTimeConverter()
            : base()
        {
            serializabletypeslist = new Type[] { typeof( DateTime ) };
            deserializabletypeslist = new Type[] { typeof( DateTime ) };
        }

        /// <summary>
        /// Converts an IJSONObject into an NET object.
        /// </summary>
        /// <param name="o">The IJSONObject object to convert.</param>
        /// <param name="t"></param>
        /// <returns>Returns a .NET object.</returns>
        public override object Deserialize( IJavascriptObject o , Type t )
        {
            JavascriptObject ht = o as JavascriptObject;

            if ( o is JavaScriptSource )
            {
                // new Date(Date.UTC(2006,6,9,5,36,18,875))

                string s = o.ToString();

                if ( s.StartsWith( "new Date(Date.UTC(" ) && s.EndsWith( "))" ) )
                {
                    s = s.Substring( 18 , s.Length - 20 );

                    //Regex r = new Regex(@"(\d{4}),(\d{1,2}),(\d{1,2}),(\d{1,2}),(\d{1,2}),(\d{1,2}),(\d{1,3})", RegexOptions.Compiled);
                    //Match m = r.Match(s);

                    //if (m.Groups.Count != 8)
                    //    throw new NotSupportedException();

                    //int Year = int.Parse(m.Groups[1].Value);
                    //int Month = int.Parse(m.Groups[2].Value) + 1;
                    //int Day = int.Parse(m.Groups[3].Value);
                    //int Hour = int.Parse(m.Groups[4].Value);
                    //int Minute = int.Parse(m.Groups[5].Value);
                    //int Second = int.Parse(m.Groups[6].Value);
                    //int Millisecond = int.Parse(m.Groups[7].Value);

                    //DateTime d = new DateTime(Year, Month, Day, Hour, Minute, Second, Millisecond);

                    string[] p = s.Split( ',' );
                    return new DateTime( int.Parse( p[0] ) , int.Parse( p[1] ) + 1 , int.Parse( p[2] ) , int.Parse( p[3] ) , int.Parse( p[4] ) , int.Parse( p[5] ) , int.Parse( p[6] ) ).AddMinutes( UtcOffsetMinutes );
                }
                else if ( s.StartsWith( "new Date(" ) && s.EndsWith( ")" ) )
                {
                    long nanosecs = long.Parse( s.Substring( 9 , s.Length - 10 ) ) * 10000;
                    nanosecs += new DateTime( 1970 , 1 , 1 , 0 , 0 , 0 , 0 , DateTimeKind.Utc ).Ticks;
                    DateTime d1 = new DateTime( nanosecs , DateTimeKind.Utc );

                    return d1.AddMinutes( UtcOffsetMinutes ) ; // TimeZone.CurrentTimeZone.GetUtcOffset(d1).TotalMinutes);
                }
            }
            else if ( o is JavaScriptString )
            {
                DateTime d2;

                if ( DateTime.TryParseExact( o.ToString() ,
                    System.Globalization.DateTimeFormatInfo.InvariantInfo.UniversalSortableDateTimePattern ,
                    System.Globalization.CultureInfo.InvariantCulture , System.Globalization.DateTimeStyles.AllowWhiteSpaces , out d2
                    ) == true )
                {
                    return  d2.AddMinutes( UtcOffsetMinutes ) ; // TimeZone.CurrentTimeZone.GetUtcOffset(d2).TotalMinutes);
                }
            }


            if ( ht == null )
                throw new NotSupportedException();

            int Year2 = ( int )_SerializerService.Deserialize( ht["Year"] , typeof( int ) );
            int Month2 = ( int )_SerializerService.Deserialize( ht["Month"] , typeof( int ) );
            int Day2 = ( int )_SerializerService.Deserialize( ht["Day"] , typeof( int ) );
            int Hour2 = ( int )_SerializerService.Deserialize( ht["Hour"] , typeof( int ) );
            int Minute2 = ( int )_SerializerService.Deserialize( ht["Minute"] , typeof( int ) );
            int Second2 = ( int )_SerializerService.Deserialize( ht["Second"] , typeof( int ) );
            int Millisecond2 = ( int )_SerializerService.Deserialize( ht["Millisecond"] , typeof( int ) );

            DateTime d5 = new DateTime( Year2 , Month2 , Day2 , Hour2 , Minute2 , Second2 , Millisecond2 );
            return d5.AddMinutes( UtcOffsetMinutes ) ; // TimeZone.CurrentTimeZone.GetUtcOffset(d3).TotalMinutes);
        }

        /// <summary>
        /// Converts a .NET object into a JSON string.
        /// </summary>
        /// <param name="o">The object to convert.</param>
        /// <returns>Returns a JSON string.</returns>
        public override string Serialize( object o )
        {
            StringBuilder sb = new StringBuilder();
            Serialize( o , sb );
            return sb.ToString();
        }

        /// <summary>
        /// Serializes the specified o.
        /// </summary>
        /// <param name="o">The o.</param>
        /// <param name="sb">The sb.</param>
        public override void Serialize( object o , StringBuilder sb )
        {
            if ( !( o is DateTime ) )
                throw new NotSupportedException();

            DateTime dt = ( DateTime )o;


             dt = dt.ToUniversalTime();
            /*
            if ( Antu.Core.Ajax.Utility.Settings.OldStyle.Contains( "renderDateTimeAsString" ) )
            {
                JavaScriptUtil.QuoteString( dt.ToString( System.Globalization.DateTimeFormatInfo.InvariantInfo.UniversalSortableDateTimePattern ) , sb );
                return;
            }
            */
                sb.AppendFormat( "new Date(Date.UTC({0},{1},{2},{3},{4},{5},{6}))" ,
                    dt.Year ,
                    dt.Month - 1 ,
                    dt.Day ,
                    dt.Hour ,
                    dt.Minute ,
                    dt.Second ,
                    dt.Millisecond );
          
        }
    }
}